package dijjer.io.xfer.http.handlers;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.LinkedList;
import dijjer.io.download.Download;
import dijjer.io.store.Store;
import dijjer.io.xfer.http.HTTPResponse;
import dijjer.util.Integrity;
import dijjer.util.MD5OutputStream;
import dijjer.util.TruncatingOutputStream;
import dijjer.util.logging.Logger;

public class DownloadResponse extends HTTPResponse {

	public static final String VERSION = "$Id: DownloadResponse.java 2 2008-03-21 14:33:03Z ian.clarke $";

	public static final int MAX_RECENT_DOWNLOADS = 5;

	public static final String RECENT_DOWNLOADS_HEADER = "<tr><td><b>Filename</b></td><td><b>Size (kb)</b></td><td><b>Download Rate(kb/sec)</b></td><td><b>MD5</b> (<font color=\"#00FF00\">Good</font>, <font color=\"#FF0000\">Bad</font>, <font color=\"#000000\">Unverified</font>)</td><td><b>% From cache</b></td></tr>";

	public static LinkedList recentDownloads = new LinkedList();

	private final long _length;

	private final byte[] _initialSniffBytes;

	private final URL _reqUrl;

	private final String _lastModified;

	private final long _rangeStart;

	private final long _rangeEnd;

	public DownloadResponse(int code, String message, String contentType,
			long length, byte[] initialSniffBytes, URL reqUrl,
			String lastModified, long rangeStart, long rangeEnd) {
		super(code, message, contentType);
		_length = length;
		_initialSniffBytes = initialSniffBytes;
		_reqUrl = reqUrl;
		_lastModified = lastModified;
		_rangeStart = rangeStart;
		_rangeEnd = rangeEnd;
	}

	protected long getContentLength() {
		return _length;
	}

	protected void writeTo(OutputStream o) throws IOException {
		MD5OutputStream out = new MD5OutputStream(o);
		out.write(_initialSniffBytes);
		int startBlock = (int) (_rangeStart / Store.DATA_BLOCK_SIZE);
		int endBlock = (int) (_rangeEnd / Store.DATA_BLOCK_SIZE);
		OutputStream tos = new TruncatingOutputStream(out,
				DownloadHandler.INITIAL_SNIFF_BYTES
						+ (_rangeStart % Store.DATA_BLOCK_SIZE),
				(_rangeEnd - _rangeStart) + 1
						- DownloadHandler.INITIAL_SNIFF_BYTES);
		Download dl = new Download(_reqUrl, _length, _lastModified, startBlock,
				endBlock, tos);
		long startTime = System.currentTimeMillis();
		dl.start();
		long totalTime = System.currentTimeMillis() - startTime;
		String actualMD5 = out.getMD5Sum();
		String correctMD5 = downloadMd5();
		synchronized (recentDownloads) {
			while (recentDownloads.size() >= MAX_RECENT_DOWNLOADS) {
				recentDownloads.removeLast();
			}
			StringBuffer rd = new StringBuffer(200);
			rd.append("<tr>");
			rd.append("<td>"
					+ _reqUrl.toString().substring(
							_reqUrl.toString().lastIndexOf("/") + 1,
							_reqUrl.toString().length()) + "</td>");
			rd.append("<td>" + (_length / 1024) + "</td>");
			rd
					.append("<td>"
							+ ((int) ((1000f * (float) dl.getDownloaded()) / (1024f * (float) totalTime)))
							+ "</td>");
			String md5Colour;
			if (correctMD5 == null) {
				md5Colour = "#000000";
			} else {
				if (correctMD5.equalsIgnoreCase(actualMD5)) {
					md5Colour = "#00FF00";
				} else {
					md5Colour = "#FF0000";
					Logger.warning("File " + _reqUrl + " failed MD5Sum check!");
				}
			}
			rd.append("<td><font color=\"" + md5Colour + "\">" + actualMD5
					+ "</font></td>");
			rd.append("<td>"
					+ Math.min(100, (dl.getBytesFromCache() * 100)
							/ dl.getDownloaded()) + "</td>");
			rd.append("</tr>");
			recentDownloads.addFirst(rd.toString());
		}
	}

	private String downloadMd5() {
		String sum = Integrity.checksumByMD5SUM(_reqUrl);
		if (sum == null)
			sum = Integrity.checksumByDotMd5(_reqUrl);
		return sum;
	}
}
